<?php

namespace app\api\controller;

use addons\third\library\Application;
use app\admin\model\ConfigAgreement;
use app\api\model\UserAddress;
use app\api\library\Code;
use app\api\validate\LoginValidate;
use app\common\controller\Api;
use app\common\library\Auth;
use app\common\library\Sms as Smslib;
use app\common\library\Tools;
use fast\Http;
use fast\Random;
use think\Cache;
use think\Db;
use think\Model;
use think\Request;
use think\Session;


/**
 * A-登录注册相关接口
 * @ApiWeigh    (100)
 */
class Login extends Api {
	protected $noNeedLogin = ['know_deal', 'send_sms', 'login', 'register', 'update_password_sms', 'initiator_code', 'test', 'agreement_details', 'register_check', 'getAuthorizeUrl', 'getOpenId'];
	protected $noNeedRight = ['*'];

	protected $validate = null;
	protected $userModel = null;
	protected $userAddressModel = null;
	protected $agreementModel = null;

	public function __construct( Request $request = null ) {
		parent::__construct( $request );


		$this->validate         = new LoginValidate();
		$this->userModel        = new \app\admin\model\User();
		$this->userAddressModel = new UserAddress();
		$this->agreementModel   = new ConfigAgreement();
	}

	/**
	 * 获取微信授权链接
	 *
	 * @ApiTitle    (获取微信授权链接)
	 * @ApiSummary  (获取微信授权链接)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiParams   (name="url", type="string", required=true, description="url")
	 *
	 * @ApiReturnParams   (name="data", type="integer", required=true, description="授权链接")
	 */
	public function getAuthorizeUrl() {
//		$redirect_uri = urlencode( $this->param['url'] );
//		$state        = \fast\Random::alnum();
//		Session::set( 'state', $state );
//		return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$config['wechat']['app_id']}&redirect_uri={$redirect_uri}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
		$url      = $this->request->param( 'url', '', 'trim' );
		$url      = urldecode( $url );
		$config   = get_addon_config( 'third' );
		$platform = 'wechat';
		if ( !$url || !$platform || !isset( $config[$platform] ) ) {
			$this->error( '参数错误' );
		}
		$config[$platform]['callback'] = $url;

		$this->app = new Application( $config );
		if ( !$this->app->{$platform} ) {
			$this->error( __( '无效参数' ) );
		}
		$this->success( '', $this->app->{$platform}->getAuthorizeUrl() );
	}

	/**
	 * 获取授权token网页授权
	 *
	 * @ApiTitle    (获取授权token网页授权)
	 * @ApiSummary  (code换取openId)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiParams   (name="code", type="string", required=true, description="code")
	 *
	 * @ApiReturnParams   (name="data", type="integer", required=true, description="openId")
	 */
	public function getOpenId() {
		$params     = $this->request->param();
		$config     = get_addon_config( 'epay' );
		$pay_wechat = new \addons\epay\library\Wechat( $config['wechat']['app_id'], $config['wechat']['app_secret'] );
		$token      = $pay_wechat->getAccessToken( $params['code'] );
		if ( !isset( $token['openid'] ) && isset( $token['errmsg'] ) ) {
			$this->error( $token['errmsg'] );
		}
		$openid = isset( $token['openid'] ) ? $token['openid'] : '';
		if ( $openid ) {
			Session::set( "openid", $openid );
		}
		$this->success( 'openId', $openid );
	}


	/**
	 * 用户须知&协议
	 *
	 * @ApiTitle    (用户须知&协议)
	 * @ApiSummary  (获取后台设置的-用户须知富文本包含多个用户协议与-隐私协议富文本按需显示)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiReturnParams   (name="code", type="integer", required=true, description="状态码")
	 * @ApiReturnParams   (name="msg", type="string", required=true, description="提示语")
	 * @ApiReturnParams   (name="data", type="object", description="用户须知&协议富文本")
	 * @ApiReturnParams   (name="user_know", type="string", description="用户须知-上")
	 * @ApiReturnParams   (name="user_know_bottom", type="string", description="用户须知-下")
	 * @ApiReturnParams   (name="agreement", type="array", description="多个用户协议")
	 * @ApiReturnParams   (name="agreement.id", type="integer", description="协议id")
	 * @ApiReturnParams   (name="agreement.title", type="string", description="协议标题")
	 * @ApiReturnParams   (name="user_deal", type="string", description="隐私协议富文本")
	 */
	public function know_deal() {
		//用户须知-上
		$data['user_know'] = Tools::set_img_style( config( 'site.user_know' ) );
		//用户须知-下
		$data['user_know_bottom'] = Tools::set_img_style( config( 'site.user_know_bottom' ) );
		//隐私协议
		$data['user_deal'] = Tools::set_img_style( config( 'site.user_deal' ) );
		//查询后台设置的用户协议-多个
		$data['agreement'] = $this->agreementModel->field( 'id,title' )->order( ['weigh' => 'desc'] )->select();
		$this->success( '用户须知&协议', $data );
	}

	/**
	 * 用户协议详情
	 *
	 * @ApiTitle    (用户协议详情)
	 * @ApiSummary  (通过协议id获取协议详情内容)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiParams   (name="agreement_id", type="integer", required=true, description="协议ID")
	 *
	 * @ApiReturnParams   (name="code", type="integer", required=true, description="状态码")
	 * @ApiReturnParams   (name="msg", type="string", required=true, description="提示语")
	 * @ApiReturnParams   (name="data", type="object", description="用户须知&协议富文本")
	 * @ApiReturnParams   (name="id", type="integer", description="协议id")
	 * @ApiReturnParams   (name="title", type="string", description="协议标题")
	 * @ApiReturnParams   (name="content", type="string", description="协议内容-富文本")
	 * @ApiReturnParams   (name="status", type="string", description="是否公告栏滚动显示:10=不滚动,20=滚动")
	 */
	public function agreement_details() {
		//获取参数
		$params = $this->request->param();
		//验证参数
		$validates = $this->validate( $params, [
			'agreement_id|协议ID' => 'require|number',
		] );

		if ( $validates !== true ) {
			$this->error( $validates );
		}
		$info = $this->agreementModel->where( 'id', $params['agreement_id'] )->find();
		$this->success( '协议详情', $info );
	}

	/**
	 * @ApiTitle    (发送短信验证码)
	 * @ApiSummary  (根据输入的电话号发送验证码验证)
	 *
	 * @ApiParams  (name=mobile, type=integer, required=true, description="手机号")
	 *
	 * @ApiReturnParams   (name="code", type="integer", required=true, description="状态码")
	 * @ApiReturnParams   (name="msg", type="string", required=true, description="提示语")
	 * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
	 */
	public function send_sms() {
		if ( !( $this->validate->scene( 'sms' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError(), [], Code::ParamInvalid );
		}

		//当前用户id一天只可发送6此验证码
		$key = $this->auth->id . date( 'Y-m-d' );
		$num = Cache::get( $key );
		if ( $num > 50 ) {
			$this->error( '今日已达最大次数，请明日再试！' );
		}
		$rs = Smslib::send( $this->param['mobile'] );

		//如果同一个用户每获取一次验证码就将验证码次数加一，将可获取验证码的时间设置为一天
		if ( !$rs ) {
			$this->error( '验证码发送失败，请稍后再试' );
		}

		//今天剩余秒数
		$expires_in = strtotime( '23:59:59' ) - time();

		Cache::set( $key, $num + 1, $expires_in );
		$this->success( '发送验证码成功');
	}

	/**
	 * 登录接口
	 *
	 * @ApiTitle    (登录接口)
	 * @ApiSummary  (公用测试账号:16602213583,密码:123456)
	 * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
	 *
	 * @ApiParams   (name="mobile", type="string", required=true, description="手机号")
	 * @ApiParams   (name="password", type="string", required=true, description="密码")
	 *
	 * @ApiReturnParams   (name="is_bank", type="integer", required=false, description="是否填写银行卡信息:0=否,1=是")
	 * @ApiReturnParams   (name="is_address", type="integer", required=false, description="是否填写地址信息:0=否,1=是")
	 * @ApiReturnParams   (name="id", type="integer", required=true, description="用户id")
	 * @ApiReturnParams   (name="nickname", type="string", required=true, description="昵称")
	 * @ApiReturnParams   (name="mobile", type="string", required=true, description="手机号")
	 * @ApiReturnParams   (name="token", type="string", required=true, description="用户token")
	 *
	 * @ApiReturnParams   (name="code", type="integer", required=true, description="状态码:0=登录不成功,1=登陆成功")
	 * @ApiReturnParams   (name="msg", type="string", required=true, description="提示语")
	 * @ApiReturnParams   (name="data", type="object", description="未完善信息直接返回登录时的token")
	 */
	public function login() {
		if ( !( $this->validate->scene( 'login' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError() );
		}
		$mobile   = $this->param['mobile'];
		$password = $this->param['password'];

		if ( $this->auth->login( $mobile, $password ) ) {
			$userinfo = $this->auth->getUserinfo();
			//检测是否完善填写银行卡信息
			$user   = $this->auth->getUser();
			$return = [
				'is_bank'    => $userinfo['is_bank'],
				'is_address' => $userinfo['is_address'],
				'token'      => $userinfo['token']
			];
			if ( empty( $user['is_bank'] ) ) {
				$this->success( __( '请完善银行卡信息后登录！' ), $return );
			}
			//检测是否完善填写地址信息
			if ( empty( $user['is_address'] ) ) {
				$this->success( __( '请完善地址信息后登录！' ), $return );
			}

			//生成一个属于该用户的邀请码海报
            $qr_url = $user['invitation_qr'];
			if ( empty( $user['invitation_qr'] ) ) {
				$qr_url = Tools::qr_pic( $userinfo['id'] );
				$this->userModel->where( 'id', $userinfo['id'] )->update( ['invitation_qr' => $qr_url] );
			}
			$userinfo['invitation_qr'] = $this->request->domain().$qr_url;
			$this->success( '登录成功', $userinfo );
		} else {
			$this->auth->getError();
			$this->error( '密码错误' );
		}
	}

	/**
	 * 注册接口
	 *
	 * @ApiTitle    (注册接口)
	 * @ApiSummary  (注册接口-点击我已阅读并同意后注册)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiParams   (name="mobile", type="string", required=true, description="手机号")
	 * @ApiParams   (name="code", type="string", required=true, description="验证码")
	 * @ApiParams   (name="nickname", type="string", required=true, description="昵称")
	 * @ApiParams   (name="password", type="string", required=true, description="密码")
	 * @ApiParams   (name="re_password", type="string", required=true, description="确认密码")
	 * @ApiParams   (name="invitation_code", type="string", required=false, description="邀请码")
	 *
	 * @ApiReturnParams   (name="code", type="integer", required=true, description="状态码:0=注册失败,1=注册成功,1001=参数错误")
	 */
	public function register() {
		if ( !( $this->validate->scene( 'register' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError() );
		}
		//判断两次密码是否一致
		if ( $this->param['password'] !== $this->param['re_password'] ) {
			$this->error( '两次密码不一致' );
		}
		//判断短信验证码与账户是否匹配
		$result = Smslib::check( $this->param['mobile'], $this->param['code'] );
		if ( !$result ) {
			$msg = $this->auth->getError();
			$msg = $msg ? $msg : __( '验证码错误' );
			$this->error( $msg );
		}

		//如果存在
		if ( $this->userModel->where( 'mobile', $this->param['mobile'] )->count() ) {
			$this->error( '该手机号已被注册！请登录' );
		}
		//验证邀请码是否存在
		$res = Db::name( 'user' )->where( 'id', $this->param['invitation_code'] )->find();
		$invitationCode =	$this->param['invitation_code'];
		if ( !$res ) {
			$this->error( '邀请码不正确!请确认后再次尝试!' );
		}
		//注册
		$res = $this->auth->register( $this->param['mobile'], $this->param['password'], '', $this->param['mobile'], ['inviter_id' => $invitationCode, 'nickname' => $this->param['nickname'], 'identity_type' => 2] );
		if ( $res ) {
		    //生成邀请二维码
		    $new_user = $this->auth->getUser();
            $qr_url = Tools::qr_pic($new_user['id']);
            $new_user->save(['invitation_qr'=>$qr_url]);
			$this->success( '注册成功' );
		} else {
            $this->error($this->auth->getError());
        }
	}

	/**
	 * 填写银行卡信息
	 *
	 * @ApiTitle    (填写银行卡信息)
	 * @ApiSummary  (注册时、登录时未填写银行卡信息时需要填写才可登录)
	 * @ApiMethod   (POST/GET)
	 * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
	 *
	 * @ApiParams   (name="bank_name", type="string", required=true, description="所属银行")
	 * @ApiParams   (name="bank_card_no", type="string", required=true, description="银行卡号")
	 * @ApiParams   (name="bank_card_holder", type="string", required=true, description="持有人姓名")
	 */
	public function user_bank_info() {
		if ( !( $this->validate->scene( 'bank_info_write' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError() );
		}
		$res = $this->userModel->where( 'id', $this->auth->id )->update( [
			'bank_name'        => $this->param['bank_name'],
			'bank_card_no'     => $this->param['bank_card_no'],
			'bank_card_holder' => $this->param['bank_card_holder'],
		] );
		if ( $res ) {
			$this->userModel->where( 'id', $this->auth->id )->update( ['is_bank' => 1] );
			$this->success( '保存银行卡信息成功！' );
		}
	}

	/**
	 * 填写地址信息
	 *
	 * @ApiTitle    (填写地址)
	 * @ApiSummary  (注册时、登录时未填写地址信息时需要填写才可登录)
	 * @ApiMethod   (POST/GET)
	 * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
	 *
	 * @ApiParams   (name="name", type="string", required=true, description="姓名")
	 * @ApiParams   (name="mobile", type="string", required=true, description="手机号码")
	 * @ApiParams   (name="address_now", type="string", required=true, description="所在地区")
	 * @ApiParams   (name="address", type="string", required=true, description="详细地址")
	 * @ApiParams   (name="is_default", type="string", required=true, description="是否默认:0=否,1=是")
	 */
	public function user_address_info() {
		if ( !( $this->validate->scene( 'address_info_write' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError() );
		}
		$save_data = [
			'user_id'     => $this->auth->id,
			'name'        => $this->param['name'],
			'mobile'      => $this->param['mobile'],
			'address_now' => $this->param['address_now'],
			'address'     => $this->param['address'],
			'is_default'  => $this->param['is_default'],
		];

		$res = $this->userAddressModel->save( $save_data );

		if ( $res ) {
			$this->userModel->where( 'id', $this->auth->id )->update( ['is_address' => 1] );
			$this->success( '保存地址信息成功!' );
		}
	}

	/**
	 * 找回密码
	 *
	 * @ApiTitle    (忘记密码-找回密码)
	 * @ApiSummary  (通过手机号找回、重新设置密码)
	 * @ApiMethod   (POST/GET)
	 *
	 * @ApiParams   (name="mobile", type="string", required=true, description="手机号")
	 * @ApiParams   (name="password", type="string", required=true, description="新密码")
	 * @ApiParams   (name="code", type="string", required=true, description="验证码，可用注册的发送短信接口")
	 */
	public function update_password_sms() {
		if ( !( $this->validate->scene( 'back_psw' )->check( $this->param ) ) ) {
			$this->error( $this->validate->getError() );
		}

		$mobile   = $this->param['mobile'];
		$code     = $this->param['code'];
		$password = $this->param['password'];

		//通过输入的手机号查询是否注册过
		if ( $this->userModel->where( 'mobile', $mobile )->count() == 0 ) {
			$this->error( '您输入的手机号还没有注册过,请输入正确的手机号再找回密码！' );
		}
		//判断验证码是否正确
		$result = Smslib::check( $mobile, $code );
		if ( !$result ) {
			$msg = $this->auth->getError();
			$msg = $msg ? $msg : __( '验证码错误' );
			$this->error( $msg );
		}

		//生成密码盐
		$salt = Random::alnum();
		//生成加盐加密后的密码
		$new_password = Auth::instance()->getEncryptPassword( $password, $salt );
		//保存密码
		$result = $this->userModel->where( 'mobile', $mobile )->update( ['password' => $new_password, 'salt' => $salt] );
		if ( $result ) {
			$this->auth->logout();
			$this->success( '修改成功，请重新登录' );
		}
	}


	/**
	 * 测试登录-获取token-无需对接
	 */
	public function test() {
		$this->auth->direct( 1000 );

		$auth     = Auth::instance();
		$userInfo = $auth->getUserinfo();

		cookie( 'token', $userInfo['token'] );

		$this->success( '测试登录成功', $userInfo );
	}
}
